#include "encode/encode.h"
#include "decode/decode.h"
#include "parameters.h"

//openCV
#include <opencv/cv.h>
#include <opencv/highgui.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define WAIT_FOR 1*1e03 //s
//#define WAIT_FOR 0 //infinity


int main(int argc, char *argv[]) {
  printf("* This is an implementation of Tian reversible data embedding method\n");

  char fname[256], out_fname[256];
  unsigned int threshold, mode;
  arguments args;
  get_arguments(argv, argc, &args);
  threshold = args.threshold;
  mode = args.mode;
  strcpy(fname, args.fname);
  strcpy(out_fname, args.out_fname);

  //Open original image
  IplImage *img = cvLoadImage(fname, 0);

  //display original image
  cvNamedWindow("original", CV_WINDOW_AUTOSIZE);
  cvShowImage("original", img);
  
  //read bitmap size
  int width = img->width;
  int height = img->height;
  if(width % 2) {
    printf("This program is designed to work on even-width images.\n");
    exit(1);
  }

  //copy data into the bitmap
  int i, j;
  unsigned char **data = (unsigned char **)malloc(height * sizeof(unsigned char *));
  for(i=0; i<height; ++i) {
    data[i] = (unsigned char *)malloc(width * sizeof(unsigned char));
    for(j=0; j<width; ++j)
      data[i][j] = (unsigned char)(img->imageData[i*(img->widthStep)+j]);
  }

  //allocate output bitmap
  unsigned char **out_data = (unsigned char **)malloc(height * sizeof(unsigned char *));
  for(i=0; i<height; ++i)
    out_data[i] = (unsigned char *)malloc(width * sizeof(unsigned char));

  if(mode == 0) {
    //encode
    printf("mode: encode\n");
    if(args.verbose) printf("> start encoding\n");
    tian_grayscale_encode(out_data, data, height, width, threshold, NULL, args.verbose);
    //tian_grayscale_encode(out_data, data, height, width, threshold, "payload", args.verbose);
    if(args.verbose) printf("> end encoding\n");
  }
  
  else {
    //decode
    printf("mode: decode\n");
    if(args.verbose) printf("> start decoding\n");
    tian_grayscale_decode(out_data, data, height, width, args.verbose);
    if(args.verbose) printf("> end decoding\n");
  }

  //copy output data back to a new bitmap
  IplImage *output = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
  for(i=0; i<height; ++i)
    for(j=0; j<width; ++j)
      output->imageData[i*(output->widthStep)+j] = (char)out_data[i][j];
  
  //display output image
  cvNamedWindow("output", CV_WINDOW_AUTOSIZE);
  cvShowImage("output", output);
  
  //write output bitmap
  if(!cvSaveImage(out_fname, output, 0))
    printf("Could not save to: %s\n", out_fname);
  if(args.verbose) printf("> write output to: %s\n", out_fname);

  printf("> done\n");
  cvWaitKey(WAIT_FOR);

  //free memory
  for(i=0; i<height; ++i) {
    free(data[i]);
    free(out_data[i]);
  }
  free(data);
  free(out_data);
  cvReleaseImage(&img);
  cvReleaseImage(&output);

  return 0;
}
